
#include "OgreApplication.h"
#include "MyTerrain.h"




	
OgreApplication::OgreApplication(){
	this->initNull();
	this->ogre_init_settings = NULL;
}

OgreApplication::OgreApplication(OgreInitializeSettings* initsets){
	this->ogre_init_settings = initsets;
	this->initNull();
}

OgreApplication::~OgreApplication(){
	std::cout << "Shutting down OgreApplication \n";

	if(this->gPhysichandler != NULL){
		this->destroyPhysics();
	}
	
	if(this->gkeymousehandler != NULL){
		this->destroyKeyboardMouseHandler();
	}

	if(this->gSoundhandler != NULL){
		this->destroySoundHandler();
	}

	if(this->gMenuHandler != NULL){
		this->destroyMenuHandler();
	}

	this->destroyOgreBasic();
}



//initMethods

void OgreApplication::initNull(){
	this->end_mainloop = false;
	this->lRoot = NULL;
	this->lSceneManager = NULL;
	this->lWindow = NULL;
	this->lResourceGroupManager = NULL;
	this->lMaterialManager = NULL;

	this->gPhysichandler = NULL;
	this->gkeymousehandler = NULL;
	this->gSoundhandler = NULL;
	this->gMenuHandler = NULL;
}

void OgreApplication::initOgreBasic(){

	//initRoot

	this->lRoot = new Ogre::Root (this->ogre_init_settings->config_file_dir,this->ogre_init_settings->plugin_file_dir,this->ogre_init_settings->name+".LOG");

	//loadPlugins

	if( 0 >= this->ogre_init_settings->manual_plugin_feed_count){
		//this->lRoot->loadPlugins(this->ogre_init_settings->plugin_file_dir);
	}
	else{
		for(int i = 0; i < this->ogre_init_settings->manual_plugin_feed_count;i++){
			this->lRoot->loadPlugin(this->ogre_init_settings->manual_plugin_feed[i]);
		}
	}

	
	//initRenderSystem

	 const Ogre::RenderSystemList* lRenderSystemList = &(this->lRoot->getAvailableRenderers());
			if( lRenderSystemList->size() == 0 )
			{
				Ogre::LogManager::getSingleton().logMessage("Sorry, no rendersystem was found.");
				return;
			}

			Ogre::RenderSystem* lRenderSystem = NULL;
                        lRenderSystem = lRenderSystemList->at(0);
			lRoot->setRenderSystem(lRenderSystem);

			this->lRoot->initialise(false,"","");

	//initRenderSettings

			Ogre::NameValuePairList lRenderParams;

			for(int i = 0; i < this->ogre_init_settings->graphic_setting_count;i++){

				lRenderParams[this->ogre_init_settings->graphic_setting_description[i]]= this->ogre_init_settings->graphic_setting_value[i];
			
			}

			if(this->ogre_init_settings->graphic_setting_count <= 0 ||this->ogre_init_settings->show_graphic_setting_dialog){
				this->lRoot->showConfigDialog();
			}

			//RenderWindow creation

			this->lWindow = this->lRoot->createRenderWindow(this->ogre_init_settings->name,this->ogre_init_settings->window_size[0],this->ogre_init_settings->window_size[1],this->ogre_init_settings->window_fullsize,&lRenderParams);
			
			this->lWindow->setActive(true);
			this->lWindow->setAutoUpdated(false);
			this->lRoot->clearEventTimes();

			//Variable init
			
			this->lSceneManager = lRoot->createSceneManager(Ogre::ST_GENERIC,"MainSceneManager");
			this->lResourceGroupManager = &Ogre::ResourceGroupManager::getSingleton();
			this->lMaterialManager = &Ogre::MaterialManager::getSingleton();

			



}

void OgreApplication::init(){

	this->initOgreBasic();

	

while(! this->ogre_init_settings->subsystems->empty()){
				Ogre::String current = this->ogre_init_settings->subsystems->back();
				this->ogre_init_settings->subsystems->pop_back();
				
				

				if(current.compare("Physics") == 0){
					this->initPhysics();continue;
				}
	
				if(current.compare("Inputs") == 0){
					this->initInputs();continue;
				}			

				if(current.compare("Sounds") == 0){
					this->initSoundSystem();continue;
				}
				
				if(current.compare("MenuHandler") == 0){
					this->initMenuHandler();continue;
				}

				if (current.compare("Terrain") == 0){
					this->initTerrain(); continue;
				}

				std::cout << "Sorry no subsystem: "+ current +" \n";
			}
}

void OgreApplication::initPhysics(){
	
	this->gPhysichandler = new PhysicHandler (this->ogre_init_settings);
	this->gPhysichandler->init(this->lSceneManager);
}

void OgreApplication::initInputs(){
	this->gkeymousehandler = new KeyboardMouseHandler(this);
}

void OgreApplication::initSoundSystem(){
	this->gSoundhandler = new SoundHandler(this);
}

void OgreApplication::initMenuHandler(){
	this->gMenuHandler = new MenuHandler(this);
}

void OgreApplication::initTerrain(){
	//MyTerrain* t = new MyTerrain(100, "H:\\DEM\\temp\\SUB.tif", "H:\\DEM\\n41w076LCC\\final.tif", pasture, lSceneManager);
	//MyTerrain* t = new MyTerrain(200, "H:\\DEM\\n41w076GeoTiff\\n41w076.tif", "H:\\DEM\\n41w076LCC\\final.tif", pasture, lSceneManager);
	//t->createLulcPoints();
	//t->createTerrain();
	//delete t;
}
void OgreApplication::destroyOgreBasic(){

	if(this->lWindow != NULL){
        std::cout << "deleting MainWindow\n";
        lWindow->removeAllListeners();
        lWindow->removeAllViewports();
        this->lWindow = NULL;
    }
	
    if(this->lSceneManager != NULL){
        std::cout << "Deleting SceneManager\n";
        lSceneManager->getRootSceneNode()->removeAndDestroyAllChildren();
        this->lSceneManager = NULL;
    }

    if(this->lResourceGroupManager != NULL){
        std::cout << "Deleting ResourceGroup\n";
        lResourceGroupManager->shutdownAll();

        this->lResourceGroupManager = NULL;
    }

    if(this->lRoot != NULL){
        std::cout << "Deleting Root\n";
        delete lRoot;
    }
}

void OgreApplication::destroyPhysics(){
	std::cout << "Destroy Physics \n";
	delete this->gPhysichandler;
	this->gPhysichandler = NULL;
}

void OgreApplication::destroySoundHandler(){
	std::cout << "Destroy SoundHandler\n";
	delete this->gSoundhandler;
	this->gSoundhandler = NULL;
}

void OgreApplication::destroyMenuHandler(){
	std::cout << "Destroy MenuHandler\n";
	delete this->gMenuHandler;
	this->gMenuHandler = NULL;
}

void OgreApplication::destroyKeyboardMouseHandler(){
	std::cout << "Destroy Inputs\n";
	delete this->gkeymousehandler;
	this->gkeymousehandler = NULL;
}

void OgreApplication::main_loop(){

	Ogre::Timer lTimer;

	this->initStartScene();

	int countermax = 12;

	unsigned long* elapsedTimeArray = new unsigned long[countermax];
	char counter = 0;
	
	for(int i = 0; i < countermax;i++){
	elapsedTimeArray[i] = 16;
	}

	while(this->MainLoopCloseCondition()){
		
		unsigned long elapsedTime = 0;

		for(int i = 0; i < countermax;i++){
		elapsedTime = elapsedTime + elapsedTimeArray[i];
		}

		elapsedTime = elapsedTime/countermax;
		
		//std::cout << "Etime"<< elapsedTime<<"\n";
		
		if(this->gkeymousehandler != NULL) this->gkeymousehandler->handleInputs(elapsedTime);
		if(this->gSoundhandler != NULL)this->gSoundhandler->update(elapsedTime); 
		

		this->MainLoopGap1(elapsedTime);

		this->lWindow->update(false);

		if(this->gPhysichandler != NULL) this->gPhysichandler->update(elapsedTime);
		
		if(this->gMenuHandler != NULL)this->gMenuHandler->update(elapsedTime);

		this->MainLoopGap2(elapsedTime);

		this->lWindow->swapBuffers(true);

		this->MainLoopGap3(elapsedTime);

		this->lRoot->renderOneFrame();

		Ogre::WindowEventUtilities::messagePump();

		elapsedTimeArray[counter] = lTimer.getMilliseconds();
		//std::cout << "etime" << elapsedTime << "\n";
		lTimer.reset();

		counter = (counter+1)%countermax;

	}
delete [] elapsedTimeArray;
}

bool OgreApplication::MainLoopCloseCondition(){

	if(this->end_mainloop) return false;

	if(this->lWindow->isClosed()) return false;

	return true;

}

void OgreApplication::MainLoopManualAbort(){
	this->end_mainloop = true;
}

void OgreApplication::startMainLoop(){
	this->main_loop();
}
float OgreApplication::soundtest_velocity = 0.0f;
void OgreApplication::MainLoopGap1(unsigned long etime){
	Ogre::SceneNode* curnode = this->lSceneManager->getSceneNode("CubeNode");
	curnode->translate(0,0,OgreApplication::soundtest_velocity*etime*0.001f);


}

void OgreApplication::MainLoopGap2(unsigned long etime){
}

void OgreApplication::MainLoopGap3(unsigned long etime){
}

void OgreApplication::initStartScene(){

	Ogre::Camera* cam = this->createStdPlayerCam();
	cam->move(Ogre::Vector3(0,20,-100));
	cam->lookAt(0,0,0);

	this->lResourceGroupManager->createResourceGroup("FirstLoaded");
	this->lResourceGroupManager->addResourceLocation("C:\\media","FileSystem","FirstLoaded",false);
	this->lResourceGroupManager->initialiseResourceGroup("FirstLoaded");
	this->lResourceGroupManager->loadResourceGroup("FirstLoaded");

	
	

	Ogre::Light* mylight = this->lSceneManager->createLight();

		mylight->setType(Ogre::Light::LightTypes::LT_DIRECTIONAL);

			mylight->setDiffuseColour(0.8f, 0.3f, 0.3f); // this will be a red light
			mylight->setSpecularColour(1.0f, 1.0f, 1.0f);// color of 'reflected' light
 
			Ogre::SceneNode* lightSceneNode = this->lSceneManager->getRootSceneNode()->createChildSceneNode("LightNode");
			lightSceneNode->attachObject(mylight);
			lightSceneNode->pitch(Ogre::Degree(45));
			lightSceneNode->yaw(Ogre::Degree(45));

			Ogre::ColourValue lAmbientColour(0.0f, 0.0f, 0.0f);
			lSceneManager->setAmbientLight(lAmbientColour);
			this->lSceneManager->setShadowTechnique(Ogre::ShadowTechnique::SHADOWTYPE_STENCIL_ADDITIVE);

			mylight->setCastShadows(true);


			Ogre::Entity* ent = this->lSceneManager->createEntity("SoundBox","cube.mesh");

			Ogre::SceneNode* cubenode = this->lSceneManager->getRootSceneNode()->createChildSceneNode("CubeNode",Ogre::Vector3(0,20,1200));
			cubenode->scale(2.5f/102.0f,2.5f/102.0f,2.5f/102.0f);

			cubenode->attachObject(ent);

			if(this->gSoundhandler != NULL){
			this->gSoundhandler->setListenerCamera(cam);

			
			//this->gSoundhandler->createStaticSound("explosion_test.wav","GeneralSounds",Ogre::Vector3(0,0,0));
			this->gSoundhandler->createStaticSound("bullet_sboom.wav","GeneralSounds",Ogre::Vector3(100,0,0));
			this->gSoundhandler->createSound("std_motor.wav","GeneralSounds",Ogre::Vector3(0,0,0),cubenode,true);
			}
			//this->gSoundhandler->createScreenSound("alert.wav","GeneralSounds");
			
			//this->gSoundhandler->createStream("alert.wav",false);

			

			//this->gSoundhandler->createSound("std_motor.wav",true,true,1500,500,&Ogre::Vector3(0,0,0),cubenode);
			
			

			/*
	Ogre::Entity* ent = this->lSceneManager->createEntity("Penguin","penguin.mesh");


	Ogre::SceneNode* cubenode = this->lSceneManager->getRootSceneNode()->createChildSceneNode("Penguinnode");
	cubenode->attachObject(ent);
	cubenode->yaw(Ogre::Degree(180));
	
	

			
			
			if(false)
			{
				

			

			std::cout << "PlaySoundFire\n";

			int soundFireGun = this->gSoundhandler->getSoundManager()->CreateSound(Ogre::String("alert.wav"),SOUND_TYPE::SOUND_TYPE_3D_SOUND);
			

			int channelFireGun = -1;
   this->gSoundhandler->getSoundManager()->PlaySound(soundFireGun,scNode, &channelFireGun);
   this->gSoundhandler->getSoundManager()->GetSoundChannel(channelFireGun)->setVolume(1.0f);
			}*/
	if(this->gPhysichandler != NULL){
		this->gPhysichandler->initTestScene();
	}
}

Ogre::Camera* OgreApplication::createStdPlayerCam(){

	Ogre::SceneNode* lnode = this->lSceneManager->getRootSceneNode()->createChildSceneNode("PlayerCameraNode");

	Ogre::Camera* lcam = this->lSceneManager->createCamera("PlayerCamera");

	Ogre::Viewport* lview = this->lWindow->addViewport(lcam,100);

	lview->setAutoUpdated(true);

	float ratio = lview->getActualWidth()/lview->getActualHeight();
	lcam->setAspectRatio(ratio);

	lcam->setNearClipDistance(1.5f);
	lcam->setFarClipDistance(3000.0f);

	lview->setBackgroundColour(Ogre::ColourValue(0,1,0,1));

	lnode->attachObject(lcam);

	return lcam;
}

//get_methods

PhysicHandler* OgreApplication::getPhysicHandler(){
	return this->gPhysichandler;
}

OgreInitializeSettings* OgreApplication::getInitSettings(){
	return this->ogre_init_settings;
}

Ogre::RenderWindow* OgreApplication::getMainWindow(){
	return this->lWindow;
}

Ogre::SceneManager* OgreApplication::getSceneManager(){
	return this->lSceneManager;
}

KeyboardMouseHandler* OgreApplication::getKeyboardMouseHandler(){
	return this->gkeymousehandler;
}

Ogre::ResourceGroupManager* OgreApplication::getResourceGroupManager(){
return this->lResourceGroupManager;
}

MenuHandler* OgreApplication::getMenuHandler(){
	return this->gMenuHandler;
}

SoundHandler* OgreApplication::getSoundHandler(){
	return this->gSoundhandler;
}